package com.company.learnjpa.model.repository;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Order;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.transaction.Transactional;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * JPA通用DAO父类，提供基础CRUD操作
 *
 * @param <T> 实体类型
 * @param <ID> 实体主键类型
 */
public abstract class GenericRepository<T, ID extends Serializable> implements Serializable {

    // 实体类类型
    private final Class<T> entityClass;

    // 注入实体管理器
    @PersistenceContext
    protected EntityManager entityManager;

    /**
     * 构造方法，获取实体类类型
     *
     * @param entityClass 实体类的Class对象
     */
    protected GenericRepository(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    /**
     * 保存实体
     *
     * @param entity 要保存的实体
     * @return 保存后的实体（包含生成的ID）
     */
    @Transactional
    public T save(T entity) {
        entityManager.persist(entity);
        return entity;
    }

    /**
     * 更新实体
     *
     * @param entity 要更新的实体
     * @return 更新后的实体
     */
    @Transactional
    public T update(T entity) {
        return entityManager.merge(entity);
    }

    /**
     * 根据ID删除实体
     *
     * @param id 实体ID
     */
    @Transactional
    public void delete(ID id) {
        T entity = findById(id);
        if (entity != null) {
            entityManager.remove(entity);
        }
    }

    /**
     * 根据ID查找实体
     *
     * @param id 实体ID
     * @return 找到的实体，若不存在则返回null
     */
    public T findById(ID id) {
        return entityManager.find(entityClass, id);
    }

    /**
     * 查询所有实体
     *
     * @return 所有实体的列表
     */
    public List<T> findAll() {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass);
        criteriaQuery.from(entityClass);
        return entityManager.createQuery(criteriaQuery).getResultList();
    }

    /**
     * 批量查询实体（分页）
     *
     * @param start 起始位置
     * @param maxResults 最大结果数
     * @return 分页查询结果
     */
    public List<T> findAll(int start, int maxResults) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass);
        criteriaQuery.from(entityClass);
        return entityManager.createQuery(criteriaQuery)
                .setFirstResult(start)
                .setMaxResults(maxResults)
                .getResultList();
    }

    /**
     * 获取实体总数
     *
     * @return 实体总数量
     */
    public long count() {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
        criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(entityClass)));
        return entityManager.createQuery(criteriaQuery).getSingleResult();
    }

    /**
     * 强制刷新实体状态
     *
     * @param entity 要刷新的实体
     */
    public void refresh(T entity) {
        entityManager.refresh(entity);
    }

    /**
     * 根据指定的字段及值进行查询
     *
     * @param params map key-字段名 value-对应的值
     * @param sortFields 排序字段，-开始的表示降序
     * @return
     */
    public List<T> findByFields(Map<String, Object> params, String... sortFields) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<T> query = cb.createQuery(entityClass);
        Root<T> root = query.from(entityClass);

        if (!params.isEmpty()) {
            List<Predicate> predicates = new ArrayList<>();
            // 动态构建查询条件
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String fieldName = entry.getKey();
                Object value = entry.getValue();

                if (value != null) {
                    Path<Object> path = root.get(fieldName);
                    predicates.add(cb.equal(path, value));
                }
            }
            query.where(predicates.toArray(new Predicate[0]));
        }

        // 动态构建排序条件
        if (sortFields != null && sortFields.length > 0) {
            List<Order> orders = new ArrayList<>();

            for (String sortField : sortFields) {
                boolean isAscending = true;
                String field = sortField;
                // 处理排序方向（前缀带 '-' 表示降序）
                if (sortField.startsWith("-")) {
                    isAscending = false;
                    field = sortField.substring(1);
                }
                Path<?> path = root.get(field);
                orders.add(isAscending ? cb.asc(path) : cb.desc(path));
            }
            query.orderBy(orders);
        }

        return entityManager.createQuery(query).getResultList();
    }

    public T findOneByFields(Map<String, Object> params) {
        List<T> results = findByFields(params);
        if (results.size() == 1) {
            return results.get(0);
        } else {
            return null;
        }
    }
}
